package com.gitee.wsl.compose.ext.text

import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontFamily
import com.gitee.wsl.compose.ext.text.span.SpanManager
import com.gitee.wsl.compose.ui.richtext.content.Format

/**
 * Returns URLs attached on this AnnotatedString.
 *
 * @param start the start of the query range, inclusive.
 * @param end the end of the query range, exclusive.
 * @return a list of URLs stored in [AnnotatedString.Range].
 *  Notice that All annotations that intersect with the range
 *  [start, end) will be returned. When [start] is bigger than
 *  [end], an empty list will be returned.
 */
 fun AnnotatedString.getURLs(
    start: Int,
    end: Int
): List<AnnotatedString.Range<String>> {
    return getStringAnnotations(URL_TAG, start, end)
}

fun String.toAnnotatedString(fontFamily: FontFamily? = null): AnnotatedString {
    return if (fontFamily != null && fontFamily != FontFamily.Default) {
        buildAnnotatedString {
            append(this@toAnnotatedString)
            addStyle(SpanStyle(fontFamily = fontFamily), 0, length)
        }
    } else {
        AnnotatedString(this)
    }
}


/**
 * Returns true if [getURLs] with the same parameters
 * would return a non-empty list
 */
 fun AnnotatedString.hasURL(
    start: Int,
    end: Int
): Boolean {
    return hasStringAnnotations(URL_TAG, start, end)
}

/**
 * The annotation tag used to distinguish urls.
 */
private const val URL_TAG = "com.gitee.wsl.compose.ext.urlAnnotation"


fun AnnotatedString.splitAnnotatedString(): List<AnnotatedString> {
    if (this.isEmpty()) return listOf(AnnotatedString(""))

    val result = mutableListOf<AnnotatedString>()
    var currentIndex = 0

    this.text.split('\n').forEach { lineText ->
        val endIndex = currentIndex + lineText.length

        // Create a new AnnotatedString for this line
        val lineAnnotatedString = buildAnnotatedString {
            // Append the line text
            append(lineText)

            // Copy over all relevant spans for this line segment
            this@splitAnnotatedString.spanStyles.forEach { span ->
                val spanStart = span.start
                val spanEnd = span.end

                // Check if this span overlaps with our current line
                if (spanStart < endIndex && spanEnd > currentIndex) {
                    // Calculate the overlapping region
                    val overlapStart = maxOf(spanStart - currentIndex, 0)
                    val overlapEnd = minOf(spanEnd - currentIndex, lineText.length)

                    if (overlapStart < overlapEnd) {
                        addStyle(span.item, overlapStart, overlapEnd)
                    }
                }
            }

            // Copy over all relevant paragraph styles
            this@splitAnnotatedString.paragraphStyles.forEach { paragraph ->
                val paragraphStart = paragraph.start
                val paragraphEnd = paragraph.end

                // Check if this paragraph style overlaps with our current line
                if (paragraphStart < endIndex && paragraphEnd > currentIndex) {
                    // Calculate the overlapping region
                    val overlapStart = maxOf(paragraphStart - currentIndex, 0)
                    val overlapEnd = minOf(paragraphEnd - currentIndex, lineText.length)

                    if (overlapStart < overlapEnd) {
                        addStyle(paragraph.item, overlapStart, overlapEnd)
                    }
                }
            }
        }

        result.add(lineAnnotatedString)
        currentIndex = endIndex + 1 // +1 for the newline character
    }

    return result
}


fun AnnotatedString.mergeAnnotatedStrings(
    start: Int,
    end: Int = start, // For insertions, start == end
    newText: AnnotatedString? = null
): AnnotatedString = buildAnnotatedString {
    // Add text outside the affected range
    append(text.substring(0, start))
    if (newText != null) append(newText.text)
    append(text.substring(end))

    // Process spans with SpanManager
    val processedSpans = SpanManager.processSpans(
        originalText = this@mergeAnnotatedStrings,
        insertionPoint = if (newText != null) start else -1,
        insertedText = newText,
        deletionStart = if (end > start) start else -1,
        deletionEnd = if (end > start) end else -1
    )

    // Add processed spans to the result
    processedSpans.forEach { span ->
        addStyle(span.item, span.start, span.end)
    }
}

fun AnnotatedString.getConsumableAnnotations(textFormatObjects: Map<String, Any>, offset: Int): Sequence<Format.Link> =
    getStringAnnotations(Format.FormatAnnotationScope, offset, offset)
        .asSequence()
        .mapNotNull {
            Format.findTag(
                it.item,
                textFormatObjects
            ) as? Format.Link
        }




